#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import json
import platform

import pexpect

from oracle import logger
from common.common import output_result_file
from common.const import ExecuteResultEnum
from common.parse_parafile import ParamFileUtil, get_env_variable
from common.schemas.thrift_base_data_type import ActionResult

from oracle.services.resource.oracle_resource_service import OracleResourceService
from oracle.common.common import send_params_to_pexpect
from oracle.common.constants import PluginPathConstant, RootCommand, ErrorCode, ScriptExitCode
from oracle.services.threshold_check.check_archive_area_windows import OracleWindowsCheckArchive


class OracleCheckArchiveAreaService:
    @staticmethod
    def check_archive_area(pid):
        logger.info(f"Start check archive area, pid={pid}.")
        response = ActionResult(code=ExecuteResultEnum.INTERNAL_ERROR.value)
        response.body_err = ErrorCode.ERROR_COMMON_SCRIPT_EXEC_FAILED.value
        params_list = OracleCheckArchiveAreaService.get_params_list_for_check_threshold(pid)
        if not params_list:
            logger.error(f"No database name matched, pid={pid}.")
            output_result_file(pid, response.dict(by_alias=True))
            return
        logger.info(f"Start to check threshold, pid={pid}.")
        db_name_list = []
        for params in params_list:
            try:
                flag, db_name_list = OracleCheckArchiveAreaService.get_message_for_output(pid, params, db_name_list)
            except Exception as exception:
                logger.error(f"Check archive area fail, exception={exception}, pid={pid}.")
            if not flag:
                output_result_file(pid, response.dict(by_alias=True))
                return
        logger.info(f"Get all db_name who over archive area, db_name_list={db_name_list} pid={pid}.")
        response = ActionResult(code=ExecuteResultEnum.SUCCESS.value)
        if db_name_list:
            response.message = '&'.join(db_name_list) + f',{params_list[0].get("ArchiveThreshold")}'
        output_result_file(pid, response.dict(by_alias=True))

    @staticmethod
    def get_message_for_output(pid, params, db_name_list):
        flag, db_name = OracleCheckArchiveAreaService.check_archive_threshold(pid, params)
        if not flag:
            return False, []
        elif db_name:
            db_name_list.append(db_name)
        return True, db_name_list

    @staticmethod
    def get_params_list_for_check_threshold(pid):
        logger.info(f"Start to get info, pid={pid}.")
        # 读取参数文件
        if platform.system().lower() == "windows":
            file_content = ParamFileUtil.parse_param_windows_file(pid)
        else:
            file_content = ParamFileUtil.parse_param_file(pid)
        db_infos = file_content.get('dbInfos')
        if not db_infos:
            return []
        params_list = []
        for index, db_info in enumerate(db_infos):
            oracle_user = db_info.get('oracleUser')
            grid_user = db_info.get('gridUser')
            db_name = db_info.get('dbName')
            db_user = db_info.get('dbUser', '')
            db_password = get_env_variable(f'dbInfos_{index}_dbPassword_{pid}')
            access_oracle_home = db_info.get('accessOracleHome', '')
            access_oracle_base = db_info.get('accessOracleBase', '')
            resources, _ = OracleResourceService.query_database(pid, oracle_user, grid_user, db_name, db_user=db_user,
                                                                db_password=db_password, oracle_base=access_oracle_base,
                                                                oracle_home=access_oracle_home)
            for resource in resources:
                if resource.extend_info.get('db_name').upper() != db_info.get('dbName').upper():
                    continue
                oracle_home = resource.extend_info.get('oracle_home', '')
                params = {
                    'DatabaseName': db_info.get('dbName'),
                    'InstanceName': db_info.get('instanceName'),
                    'ArchiveThreshold': db_info.get('archThreshold'),
                    'UserName': db_info.get('dbUser', ''),
                    'Password': get_env_variable(f'dbInfos_{index}_dbPassword_{pid}'),
                    'OracleHome': oracle_home,
                    'ASMInstanceName': db_info.get('asmName'),
                    'AccessOracleBase': access_oracle_base,
                    'AccessOracleHome': access_oracle_home
                }
                params_list.append(params)
        return params_list

    @staticmethod
    def check_archive_threshold(pid, params):
        logger.info(f"Create params_content, pid={pid}")
        # windows适配
        if platform.system().lower() == "windows":
            instance_name = params.get("InstanceName", "")
            db_user = params.get("UserName", "")
            db_password = params.get("Password", "")
            oracle_home = params.get("OracleHome", "")
            db_archive_limen = params.get("ArchiveThreshold", "")
            oracle_check_archive = OracleWindowsCheckArchive(pid, instance_name, db_user, db_password)
            ret_code = oracle_check_archive.oracle_windows_check_archive(oracle_home, db_archive_limen)
            if ret_code == ScriptExitCode.SUCCESS:
                return True, ''
            if ret_code != ScriptExitCode.ERROR_ORACLE_OVER_ARCHIVE_USING:
                logger.error(f"Exit check area script,return code={ret_code}, pid={pid}")
                return False, ''
            return True, params.get('DatabaseName')
        # 调用脚本
        child = pexpect.spawn(
            f"sh {PluginPathConstant.SCRIPTS_PATH.value}/{RootCommand.ROOT_COMMAND_SCRIPT_CHECKARCHIVETHRESHOLD.value} "
            f"{PluginPathConstant.SCRIPTS_PATH.value} {pid} {len(params)}",
            encoding='utf-8')
        send_params_to_pexpect(params, child)
        child.expect(pexpect.EOF)
        child.close()
        logger.info(f"Get child.exitstatus={child.exitstatus}, pid={pid}")
        if child.exitstatus == ExecuteResultEnum.SUCCESS.value:
            return True, ''
        if child.exitstatus != ScriptExitCode.ERROR_ORACLE_OVER_ARCHIVE_USING:
            logger.error(f"Exit check area script,return code={child.exitstatus}, pid={pid}")
            return False, ''
        return True, params.get('DatabaseName')
